<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="zh-CN" />
<link href="../style/css/manual-zip.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" />
<link href="../style/css/manual-zip-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" />
<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" />
<title>服务器端包含入门 － Apache 2.2 中文手册 [金步国]</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head>
<body id="manual-page"><div id="page-header">
<p class="menu"><a href="../mod/index.html">模块索引</a> | <a href="../mod/directives.html">指令索引</a> | <a href="../faq/index.html">常见问题</a> | <a href="../glossary.html">词汇表</a> | <a href="../sitemap.html">站点导航</a></p><p class="apache">Apache HTTP Server 版本2.2</p><img alt="" src="../images/feather.gif" /></div>
<div class="up"><a href="index.html"><img title="&lt;-" alt="&lt;-" src="../images/left.gif" /></a></div>
<div id="path"><a href="https://www.apache.org/">Apache</a> &gt; <a href="https://httpd.apache.org/">HTTP Server</a> &gt; <a href="https://httpd.apache.org/docs/">文档</a> &gt; <a href="../index.html">版本2.2</a> &gt; <a href="index.html">如何.../指南</a></div>

<div id="translation-info">　　 <a href="../translator_announcement.html#thanks">致谢</a> | 本篇译者：<a href="../../../index.html">金步国</a>(<a href="../../../index.html">作品集</a>) | 本页最后更新：2006年10月20日</div>
<div id="page-content"><div id="preamble"><h1>服务器端包含入门</h1>


<p>服务器端包含提供了一种对现有HTML文档增加动态内容的方法。</p>
</div>
	<div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="related" id="related">简介</a></h2>
 <table border="1" cellpadding="0" cellspacing="0" bordercolor="#AAAAAA" class="related">
<tr><th>相关模块</th><th>相关指令</th></tr>
<tr><td><ul><li><code class="module"><a href="../mod/mod_include.html">mod_include</a></code></li><li><code class="module"><a href="../mod/mod_cgi.html">mod_cgi</a></code></li><li><code class="module"><a href="../mod/mod_expires.html">mod_expires</a></code></li></ul></td><td><ul><li><code class="directive"><a href="../mod/core.html#options">Options</a></code></li><li><code class="directive"><a href="../mod/mod_include.html#xbithack">XBitHack</a></code></li><li><code class="directive"><a href="../mod/mod_mime.html#addtype">AddType</a></code></li><li><code class="directive"><a href="../mod/core.html#setoutputfilter">SetOutputFilter</a></code></li><li><code class="directive"><a href="../mod/mod_setenvif.html#browsermatchnocase">BrowserMatchNoCase</a></code></li></ul></td></tr>
</table>

    <p>本文针对服务器端包含(SSI)讨论如何配置服务器以允许SSI ，并介绍一些对现有HTML页面增加动态内容的基本SSI技术。</p>

    <p>本文后部将讨论用SSI做一些稍微高级的事情，比如SSI指令中的条件语句。</p>

</div><div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="what" id="what">什么是SSI ?</a></h2>

    <p>SSI是嵌入HTML页面中的指令，在页面被提供时由服务器进行运算，以对现有HTML页面增加动态生成的内容，而无须通过CGI程序提供其整个页面，或者使用其他动态技术。</p>

    <p>至于什么时候应当用SSI ，而什么时候应当用某些程序生成整个页面，取决于页面中有多少内容是静态的，又有多少内容需要在每次页面被提供时重新计算。SSI是一种增加小段动态信息的好方法，比如当前时间。如果你的页面大部分内容是在被提供时动态生成的，那就要另找方案了。</p>
</div><div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="configuring" id="configuring">配置服务器以允许SSI</a></h2>


    <p>要使服务器允许SSI ，必须在<code>httpd.conf</code>或<code>.htaccess</code>文件中有如下配置：</p>
	<div class="example"><p><code>
        Options +Includes
</code></p></div>

    <p>这样就告诉服务器允许解析文件中的SSI指令。注意，在多数配置中，多个<code class="directive"><a href="../mod/core.html#options">Options</a></code>指令会互相覆盖，所以可能需要对使用SSI的目录专门使用一个<code>Options</code>指令，以确保其有效。</p>

    <p>并非所有文件中的SSI指令都会被解析，必须告诉Apache应该解析哪些文件。有两种方法使Apache解析带有特定后缀名的文件，比如：<code>.shtml</code> ，配置如下：</p>
	<div class="example"><p><code>
        AddType text/html .shtml<br />
	AddOutputFilter INCLUDES .shtml
</code></p></div>

    <p>该方法的缺点之一是，为了使文件具有<code>.shtml</code>后缀从而执行其中的指令，需要加入SSI指令的现有文件的名字，以及所有指向此页面的连接。</p>

    <p>另一种方法是，使用<code class="directive"><a href="../mod/mod_include.html#xbithack">XBitHack</a></code>指令：</p>
<div class="example"><p><code>
        XBitHack on
</code></p></div>

    <p><code class="directive"><a href="../mod/mod_include.html#xbithack">XBitHack</a></code>告诉Apache解析所有设置了执行位的文件中的SSI指令。这样，无需修改文件名，只要用<code>chmod</code>使文件变成可执行的，就可以对现有页面增加SSI指令。</p>
	<div class="example"><p><code>
        chmod +x pagename.html
</code></p></div>

    <p>这里简要说明一点：偶然会有人向你推荐，无须用带<code>.shtml</code>的文件名，只要使Apache解析所有<code>.html</code>文件的SSI就可以了。那些人可能没听说过<code class="directive"><a href="../mod/mod_include.html#xbithack">XBitHack</a></code> 。要知道，这样做会使Apache在发送文件到客户端之前通读此文件，即使其中并没有任何SSI指令，从而对速度有很不利的影响，所以这并不是好办法。</p>

    <p>当然，在Windows上，没有对应的执行位可以设置，所以对你的配置方法就有一些限制。</p>

    <p>在默认配置的情况下，Apache不会为SSI页面发送最后修改日期或者内容长度的HTTP头，因为这些值对动态页面来说难以确定。这样会阻止页面被缓冲，导致客户端性能有明显的下降。有两种解决方法：</p>

    <ol>
      <li>设置 <code>XBitHack Full</code> ，告诉Apache在判断最后修改日期时，只查看被请求文件本身的日期，而忽略其中包含的其它文件的修改日期。</li>

      <li>使用<code class="module"><a href="../mod/mod_expires.html">mod_expires</a></code>提供的指令为文件设置一个明确的过期时间，并告诉浏览器和代理这个文件可以被缓冲。</li>
    </ol>
</div><div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="basic" id="basic">基本SSI指令</a></h2>

    <p>SSI指令有如下语法：</p>
<div class="example"><p><code>
        &lt;!--#element attribute=value attribute=value ... --&gt;
</code></p></div>

    <p>类似于HTML注释，即使没有正确配置SSI ，它也不会被浏览器显示，但在HTML代码中可见。而若正确配置了SSI ，则指令会被其结果所取代。</p>

    <p>其中的元素可以有许多，我们会在下一个版本的文档中讨论其中的大多数，而在这里，仅举几个SSI的例子。</p>

<h3><a name="todaysdate" id="todaysdate">今天的日期</a></h3>

<div class="example"><p><code>
        &lt;!--#echo var="DATE_LOCAL" --&gt;
</code></p></div>

    <p><code>echo</code>元素用于显示一个变量的值。标准变量有很多，其中包含对CGI程序有效的所有环境变量。并且还可以用<code>set</code>元素定义你自己的专用变量。</p>

    <p>如果你不喜欢这种日期格式，可以用<code>config</code>元素的<code>timefmt</code>属性，改变其格式。</p>

<div class="example"><p><code>
        &lt;!--#config timefmt="%A %B %d, %Y" --&gt;<br />
        Today is &lt;!--#echo var="DATE_LOCAL" --&gt;
</code></p></div>


<h3><a name="lastmodified" id="lastmodified">文件的修改日期</a></h3>

<div class="example"><p><code>
        This document last modified &lt;!--#flastmod file="index.html" --&gt;
</code></p></div>

    <p>这个元素使用<code>timefmt</code>的格式配置。</p>


<h3><a name="cgi" id="cgi">包含一个CGI程序的输出结果</a></h3>

    <p>这也是SSI很常见的一个用途：包含一个CGI程序的输出，比如人人喜欢的"点击计数器"。</p>

	<div class="example"><p><code>
        &lt;!--#include virtual="/cgi-bin/counter.pl" --&gt;
</code></p></div>


</div><div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="additionalexamples" id="additionalexamples">附加的例子</a></h2>


    <p>以下是一些在HTML中使用SSI的特殊例子。</p>

	<h3><a name="docmodified" id="docmodified">文档是什么时候被修改的?</a></h3>

    <p>前面我们提到过可以用SSI告诉用户文档是什么时候被修改的，但是具体实现方法却未说明。将以下代码放到HTML中，会在页面中产生一个时间戳，当然，你必须首先按前面的方法启用SSI 。</p>
	<div class="example"><p><code>
        &lt;!--#config timefmt="%A %B %d, %Y" --&gt;<br />
        This file last modified &lt;!--#flastmod file="ssi.shtml" --&gt;
</code></p></div>

    <p>不用说，你应该用你实际引用的文件名来替换<code>ssi.shtml</code> ，所以，如果你想简单地在所有文件中使用这段通用代码以达到这个目的，这个方法就并不方便，就需要用到<code>LAST_MODIFIED</code> 变量：</p>
	<div class="example"><p><code>
        &lt;!--#config timefmt="%D" --&gt;<br />
        This file last modified &lt;!--#echo var="LAST_MODIFIED" --&gt;
</code></p></div>

    <p>有关<code>timefmt</code>格式的细节，可以到<a href="https://www.google.com/">google</a>查找<code>strftime</code> ，其语法是相同的。</p>


	<h3><a name="standard-footer" id="standard-footer">包含一个标准页脚</a></h3>


    <p>当你管理一个拥有许多页面的站点，你会发现对所有页面同时做改动是很痛苦的，尤其是在试图对所有页面维持某种标准视觉效果的时候。</p>

    <p>使用包含一个页眉/页脚的方法，可以减轻修改的负担。你只要制作一个页脚文件，并用<code>include</code>命令包含到每个页面即可。<code>include</code>元素能按<code>file</code>属性或<code>virtual</code>属性判断应该包含的文件。<code>file</code>属性是一个<em>相对于当前目录</em>的文件路径，即不能是一个绝对路径(以"/"开头)或包含"../"的路径。<code>virtual</code>属性可能更有用，它是一个相对于被提供的文档的URL ，可以以"/"开头，但必须与被提供的文档位于同一服务器上。</p>
	<div class="example"><p><code>
        &lt;!--#include virtual="/footer.html" --&gt;
</code></p></div>

    <p>SSI指令和页脚文件相结合使用是很有用的，比如在页脚文件中使用<code>LAST_MODIFIED</code>指令。SSI指令可以出现在包含文件中，而<code>include</code>可以嵌套，即一个包含文件还可以再包含另外一个。</p>


</div><div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="config" id="config">我还能设置其它什么？</a></h2>


    <p><code>config</code>除了能设置时间格式，还有两种用途。</p>

    <p>当SSI指令发生错误时，会产生如下消息：</p>
<div class="example"><p><code>
        [an error occurred while processing this directive]
</code></p></div>

    <p>为了改变消息的形式，可以使用<code>config</code>元素的<code>errmsg</code>属性：</p>
<div class="example"><p><code>
        &lt;!--#config errmsg="[It appears that you don't know how to use SSI]" --&gt;
</code></p></div>

    <p>希望最终用户永远也不会看到这个消息，因为在网站投入运行之前你已经把这些问题都解决了。是吗？</p>

    <p>还可以使用<code>config</code>的<code>sizefmt</code>属性设置返回的文件大小的格式，或者是以<code>bytes</code>为单位，或者是以Kb或Mb为单位的<code>简写(abbrev)</code>。</p>
    </div><div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="exec" id="exec">执行命令</a></h2>


    <p>我期望未来几个月内能再写一篇小型的CGI程序使用SSI的文章，而这里仅介绍<code>exec</code>的使用。SSI确实可以利用shell(<code>/bin/sh</code> ，精确地说，还可以是Win32中的DOS shell)来执行命令。下例产生一个目录列表：</p>
	<div class="example"><p><code>
        &lt;pre&gt;<br />
        &lt;!--#exec cmd="ls" --&gt;<br />
        &lt;/pre&gt;
</code></p></div>

    <p>或者在Windows中：</p>
<div class="example"><p><code>
        &lt;pre&gt;<br />
        &lt;!--#exec cmd="dir" --&gt;<br />
        &lt;/pre&gt;
</code></p></div>

    <p>你可能会发现，在Windows中这个指令的结果有些奇怪，<code>dir</code>的输出中包含有字符串"&lt;<code>dir</code>&gt;"，它会使浏览器产生混淆。</p>

    <p>注意，这个功能是<strong>极度危险</strong>的，因为它会执行任何包含在<code>exec</code>标记中的命令。如果用户有可能修改你的网页内容，比如"留言本"，那么你一定要关闭这个功能。可以在<code>Options</code>指令中加上<code>IncludesNOEXEC</code>参数，以关闭<code>exec</code>功能，同时又保留SSI。</p>
    </div><div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="advanced" id="advanced">高级SSI技术</a></h2>


    <p>除了分离内容，Apache SSI还有设置变量的操作，并且还可以将这些变量用在比较和条件表达式中。</p>

	<h3><a name="caveat" id="caveat">警告</a></h3>

    <p>本文中讨论的大多数功能仅在Apache1.2及更新版本中有效。如果你运行的不是Apache1.2及更新版本，请立刻或者尽快升级，现在就动手，我们会等你弄好了再继续往下讲。</p>


<h3><a name="variables" id="variables">设置变量</a></h3>

    <p>使用<code>set</code>指令可以设置变量以备后用，其语法是：</p>
<div class="example"><p><code>
        &lt;!--#set var="name" value="Rich" --&gt;
</code></p></div>

    <p>除了设置字面变量以外，还可以设置其他任何变量，比如<a href="../env.html">环境变量</a>和此前提到过的一些变量(如<code>LAST_MODIFIED</code>)，作为你的专用变量。在变量名前面缀以"$"，表示它是一个变量，而不是一个字面字符串。</p>

    <div class="example"><p><code> &lt;!--#set var="modified" value="$LAST_MODIFIED" --&gt;
    </code></p></div>

    <p>若要在字面字符串中使用"$"，必须使用转义符号"\$"：</p>
	<div class="example"><p><code>
        &lt;!--#set var="cost" value="\$100" --&gt;
</code></p></div>

    <p>最后，如果要在较长的字符串中使用变量，可以用花括号把变量名括起来，以免变量名与其他字符混淆(要对这种情况举例说明有点难度，但还是希望你能领会)。</p>
<div class="example"><p><code>
        &lt;!--#set var="date" value="${DATE_LOCAL}_${DATE_GMT}" --&gt;
</code></p></div>


<h3><a name="conditional" id="conditional">条件表达式</a></h3>


    <p>有了变量，就可以设置和比较它们的值以表示条件，SSI也因此成为一种简洁的编程语言。<code class="module"><a href="../mod/mod_include.html">mod_include</a></code>提供了<code>if</code>, <code>elif</code>, <code>else</code>, <code>endif</code>等结构以构造条件语句，从同一个页面高效地产生多个逻辑页面。</p>

    <p>条件结构如下：</p>
	<div class="example"><p><code>
    &lt;!--#if expr="test_condition" --&gt;<br />
    &lt;!--#elif expr="test_condition" --&gt;<br />
    &lt;!--#else --&gt;<br />
    &lt;!--#endif --&gt;
</code></p></div>

    <p><em>test_condition</em>可以是任何逻辑比较：可以是一个值和另一个值比较，也可以是测试一个特定的值是否为"真"(一个给定的字符串如果非空则为真)。完整的比较操作符列表，参见<code class="module"><a href="../mod/mod_include.html">mod_include</a></code> 。以下是可能会用到的一些例子。</p>

    <p>在配置文件中，可以这样设置：</p>
<div class="example"><p><code>
        BrowserMatchNoCase macintosh Mac<br />
        BrowserMatchNoCase MSIE InternetExplorer
</code></p></div>

    <p>如果客户端在Macintosh上运行Internet Explorer，则上例设置环境变量"Mac"和"InternetExplorer"都为真。</p>

    <p>然后，在允许SSI的文档中，可以这样设置：</p>
<div class="example"><p><code>
        &lt;!--#if expr="${Mac} &amp;&amp; ${InternetExplorer}" --&gt;<br />
        Apologetic text goes here<br />
        &lt;!--#else --&gt;<br />
        Cool JavaScript code goes here<br />
        &lt;!--#endif --&gt;
</code></p></div>

    <p>我一点也不反对在Mac上运行IE，只是上个星期我花了好几个小时试图在Mac上的IE中使用JavaScript，而它在其他地方都能正常运作，以上只是一个临时的妥协方案。</p>

    <p>任何其他变量(或者是你定义的，或者是标准的环境变量)都可以用于条件语句。利用Apache的<code>SetEnvIf</code>以及其他相关指令设置环境变量，此功能可以很好地实现动态页面而无须借助于CGI。</p>

</div><div class="top"><a href="ssi.html#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="conclusion" id="conclusion">总结</a></h2>

    <p>SSI固然不能替代CGI或者其他动态页面技术，但它是在页面中插入众多小型的动态片段的优秀方法，而无须大量额外的操作。</p>
</div></div>
<div id="footer">
<p class="apache">本文允许自由的转载、引用、再分发，但必须保留译者署名并注明出处；详见：<a href="../translator_announcement.html#announcement">版权声明</a>。</p>
<p class="menu"><a href="../mod/index.html">模块索引</a> | <a href="../mod/directives.html">指令索引</a> | <a href="../faq/index.html">常见问题</a> | <a href="../glossary.html">词汇表</a> | <a href="../sitemap.html">站点导航</a></p></div>
</body></html>